﻿//	Copyright (c) 2012 Jonathan Loe
//
//	MIT license (http://en.wikipedia.org/wiki/MIT_License)
//
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights 
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
//	of the Software, and to permit persons to whom the Software is furnished to do so, 
//	subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in all 
//	copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
//	INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
//	PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
//	FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
//	ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Data.Linq.Mapping;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

using Ordinaire.Data;
using Ordinaire.Db;

namespace Ordinaire.Security.Data
{
    /// <summary>
    /// Class representation of table 'Users'.
    /// </summary>
    [Table]
    public class Users : Data<int, string>
    {
        #region Variables

        /// <summary>
        /// User password.
        /// </summary>
        private string password;

        /// <summary>
        /// User last activity date.
        /// </summary>
        private DateTime activityDate;

        /// <summary>
        /// User last login date.
        /// </summary>
        private DateTime loginDate;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets userid.
        /// </summary>
        [Column(IsPrimaryKey = true, IsDbGenerated = true, UpdateCheck = UpdateCheck.Never)]
        public override int Id
        {
            get { return base.Id; }
            set { base.Id = value; }
        }

        /// <summary>
        /// Gets or sets username.
        /// </summary>
        [Column(DbType = "nvarchar(10) NOT NULL", UpdateCheck = UpdateCheck.Never)]
        public override string Name
        {
            get { return base.Name; }
            set { base.Name = value.TrimOrEmpty().ToLower(); }
        }

        /// <summary>
        /// Gets or sets user hashed password.
        /// </summary>
        [Column(DbType = "nvarchar(max) NOT NULL", UpdateCheck = UpdateCheck.Never)]
        public string Password
        {
            get { return this.password; }
            set { this.password = value; }
        }

        /// <summary>
        /// Gets or sets last login date.
        /// </summary>
        [Column(DbType = "datetime NOT NULL", UpdateCheck = UpdateCheck.Never)]
        public DateTime LoginDate
        {
            get { return (loginDate.Ticks > 0) ? loginDate : DateTime.Now; }
            set { loginDate = value; }
        }

        /// <summary>
        /// Gets or sets last activity date.
        /// </summary>
        [Column(DbType = "datetime NOT NULL", UpdateCheck = UpdateCheck.Never)]
        public DateTime ActivityDate
        {
            get { return (loginDate.Ticks > 0) ? loginDate : DateTime.Now; }
            set { activityDate = value; }
        }

        /// <summary>
        /// Gets or sets creator's username.
        /// </summary>
        [Column(DbType = "nvarchar(10) NOT NULL", UpdateCheck = UpdateCheck.Never)]
        public override string CreatedBy
        {
            get { return base.CreatedBy; }
            set { base.CreatedBy = value.TrimOrEmpty(); }
        }

        /// <summary>
        /// Gets or sets creation date.
        /// </summary>
        [Column(DbType = "datetime NOT NULL", UpdateCheck = UpdateCheck.Never)]
        public override DateTime? CreateDate
        {
            get { return base.CreateDate; }
            set { base.CreateDate = value; }
        }

        /// <summary>
        /// Gets or sets updator's username.
        /// </summary>
        [Column(DbType = "nvarchar(10)", UpdateCheck = UpdateCheck.Never)]
        public override string UpdatedBy
        {
            get { return base.UpdatedBy; }
            set { base.UpdatedBy = value.TrimOrEmpty(); }
        }

        /// <summary>
        /// Gets or sets last update date.
        /// </summary>
        [Column(DbType = "datetime", UpdateCheck = UpdateCheck.Never)]
        public override DateTime? UpdateDate
        {
            get { return base.UpdateDate; }
            set { base.UpdateDate = value; }
        }

        #endregion

        #region Public static methods

        /// <summary>
        /// Returns an expression indicating whether both username and password are valid.
        /// </summary>
        /// <param name="username">the name of the user to validate</param>
        /// <param name="password">the hashed password of the specified user</param>
        /// <returns>relevant expression</returns>
        public static Expression<Func<Users, bool>> AreValid(string username, string password)
        {
            return user => user.Name == username && user.Password == password;
        }

        /// <summary>
        /// Returns an expression indicating whether username is the same the one specified.
        /// </summary>
        /// <param name="username">the username to match with</param>
        /// <returns>relevant expression</returns>
        public static Expression<Func<Users, bool>> UsernameIs(string username)
        {
            // [BUG] http://connect.microsoft.com/VisualStudio/feedback/details/394255/linq-to-sql-bug-handling-entities-with-common-base-class)
            return user => ((Users)user).Name == username;
        }

        #endregion
    }

    /// <summary>
    /// Contains all extension methods related to Ordinaire.Security.Data.Users.
    /// </summary>
    public static class UsersExtensionMethods
    {
        /// <summary>
        /// Converts the specified Ordinaire.Security.Data.Users to Ordinaire.Security.User.
        /// </summary>
        /// <param name="data">user data</param>
        /// <param name="providerName">the ProviderName string for the membership user</param>
        /// <returns>new instance of Ordinaire.Security.User</returns>
        public static User ToUser(this Users data, string providerName)
        {
            if (data == null)
            {
                return null;
            }

            return new User(data.Name, providerName, data.CreateDate.Value, data.LoginDate, data.ActivityDate);
        }
    }
}
